package org.springframework.beans.factory.support;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author derekyi
 * @date 2020/11/22
 */
//继承一个，实现俩ConfigurableListableBeanFactory没有出现在类图上
	//BeanDefinitionRegistry就是注册BeanDefinition接口，里面就是一些方法
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {


	//bean容器实际上就是一个线程安全的hashmap，名称+bean定义类
	private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);


	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
		beanDefinitionMap.put(beanName, beanDefinition);
	}

	@Override
	public BeanDefinition getBeanDefinition(String beanName) throws BeansException {
		BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
		if (beanDefinition == null) {
			throw new BeansException("No bean named '" + beanName + "' is defined");
		}

		return beanDefinition;
	}

	@Override
	public boolean containsBeanDefinition(String beanName) {
		return beanDefinitionMap.containsKey(beanName);
	}


	//这个方法在ioc容器里，beanDefinition和传入type类比较。是否有继承关系。最后存入result返回
	@Override
	public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
		Map<String, T> result = new HashMap<>();
		//遍历所有的beanDefinitionMap里的值
		beanDefinitionMap.forEach((beanName, beanDefinition) -> {
			//先得到beanDefinition里的类
			Class beanClass = beanDefinition.getBeanClass();
			//这里做条件判断type和beanClass比较。这个type我们是传过来的BeanFactoryPostProcessor
			if (type.isAssignableFrom(beanClass)) {
				//重点！我们这里把bean创建出来了。存入一个map集合。再调用这个bean的postProcessBeanFactory方法
				T bean = (T) getBean(beanName);
				result.put(beanName, bean);
			}
		});
		return result;

		//整体理解，你在xml文件里的所有beanDefinition已经注册进入了beanDefinitionMap
		//然后一个个判断，你注册的beanDefinition里是否有一个是传过来的BeanFactoryPostProcessor类的子类
		//如果是，有一个算一个，都存入我们定义的result的hashmap里
	}

	public <T> T getBean(Class<T> requiredType) throws BeansException {
		List<String> beanNames = new ArrayList<>();
		//得到所有的BeanDefinition，从map里
		for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
			Class beanClass = entry.getValue().getBeanClass();
			//这里是先把class拿出来，再判断是否相同（这样即使父类也可以面前用）
			if (requiredType.isAssignableFrom(beanClass)) {
				//如果符合就存入集合（集合里是所有符合条件的bean）
				beanNames.add(entry.getKey());
			}
		}
		if (beanNames.size() == 1) {
			//问题如果很多个呢？
			//如果大小为1，意思就一个符合的，直接用
			return getBean(beanNames.get(0), requiredType);
		}

		throw new BeansException(requiredType + "expected single bean but found " +
				beanNames.size() + ": " + beanNames);
	}

	@Override
	public String[] getBeanDefinitionNames() {
		Set<String> beanNames = beanDefinitionMap.keySet();
		return beanNames.toArray(new String[beanNames.size()]);
	}

	//看类名，这个还是我们的ioc容器，这个方法是提前创建单例bean对象。
	@Override
	public void preInstantiateSingletons() throws BeansException {
		beanDefinitionMap.forEach((beanName, beanDefinition) -> {
			//这里是foreach循环
			//只有当bean是单例且不为懒加载就会被直接创建

			if (beanDefinition.isSingleton() && !beanDefinition.isLazyInit()) {
				getBean(beanName);//直接创建
			}
		});
	}



}










